package com.peppa.common.grayconfig.Strategy;

import com.netflix.loadbalancer.ILoadBalancer;
import com.netflix.loadbalancer.Server;
import com.peppa.common.grayconfig.Strategy.factory.AnnoStrategy;
import com.peppa.common.grayconfig.ThreadAttributes;
import org.springframework.cloud.netflix.ribbon.eureka.EurekaServerIntrospector;

import java.util.*;

/**
 * @author ：杜戈
 * @date ：Created in 2019-08-21 17:18
 * @description：服务器端自定义tag策略，服务器上的策略字符串中类似tag1:v1;tag2:v2;
 * 如果header中也存在huohua-tag1=v1或者huohua-tag2=v2，则可以选择这个服务器
 */
@AnnoStrategy
public class ServerTagStrategy extends StrategyAbstract {
    private final String strategy_key = "gray-tag";

    public ServerTagStrategy() {
        setName(S_TAG);
        setOrder(SORT_S_TAG);
    }

    @Override
    public Server getServer(ILoadBalancer balancer){
        try {
            EurekaServerIntrospector serverIntrospector = new EurekaServerIntrospector();
            Server serverRet = null;
            int count = 0;

            while(true) {
                if (serverRet == null && count++ < 5) {
                    List<Server> servers = balancer.getAllServers();
                    List<Server> serversReach = balancer.getReachableServers();
                    if (serversReach.size() == 0 || servers.size() == 0) {
                        return null;
                    }
                    //按照eureka的metadata里的strategy_key=?来选择
                    //
                    List<Server> devlist = new ArrayList<>();
                    for (Server server : servers) {
                        Map metadata = serverIntrospector.getMetadata(server);
                        if (metadata != null && metadata.containsKey(strategy_key)) {
                            String metavalue = (String) metadata.get(strategy_key);
                            if (metavalue.equals("no"))
                                continue;
                            try {
                                if (metavalue != null && !metavalue.equals("")) {
                                    StringTokenizer stringTokenizer = new StringTokenizer(metavalue, DELIM_ITEM, false);
                                    while (stringTokenizer.hasMoreTokens()) {
                                        String stategy = stringTokenizer.nextToken().trim();
                                        int ind = stategy.indexOf(DELIM_VALUE);
                                        if(ind<=0||stategy.length()==ind+1)
                                            continue;
                                        String skey = stategy.substring(0,ind).trim();
                                        String svalue = stategy.substring(ind+1).trim();
                                        String clientheadervalue = ThreadAttributes.getHeaderValue(skey);
                                        if (clientheadervalue!=null && clientheadervalue.equals(svalue)){
                                            devlist.add(server);
                                            //此服务器已经命中，其他策略就跳过了
                                            break;
                                        }
                                    }
                                }
                            }catch (Exception e){
                                logger.error(strategy_key,e.getMessage());
                            }
                        }
                    }
                    if (devlist.size()==0)
                        return null;
                    serverRet = getRandom(devlist);
                    //做下面判断，是因为多线程情况下，Server的状态会变
                    if (serverRet == null) {
                        Thread.yield();
                    } else {
                        if (serverRet.isAlive() && serverRet.isReadyToServe()) {
                            return serverRet;
                        }
                    }
                    serverRet = null;
                    continue;
                }
                if (count >= 5) {
                    logger.warn("No available alive servers after 5 tries from load balancer: " + balancer);
                }

                return serverRet;
            }
        }catch (Exception e){
            logger.error(name.concat("选择异常"),e.getMessage());
        }
        return null;
    }
    @Override
    public String getName(){
        return name;
    }
}
